package gov.nasa.anml.lifted;
 
import gov.nasa.anml.PDDL;
import gov.nasa.anml.State;
import gov.nasa.anml.PDDL.Function;
import gov.nasa.anml.utility.SimpleObject;
import gov.nasa.anml.utility.SimpleString;
import gov.nasa.anml.utility.SimpleVoid;

// Scheme: value(State s, int contextID)
// The state is the state of all memory, including a list of the active
// contexts.  Contexts are the state of registers 
// [and the ids of executing steps that contain storage];
// context-switching then lets the same names refer to concurrent sets
// of values.  This supports parameter references.
// Also local state.  Past references can be dealt with by accumulating
// local state, or by keeping a closed list and walking up.
// The local state approach is handy for compilations to other languages

public class Parameter<T extends SimpleObject<? super T>>  extends IdentifierImp<T,SimpleVoid> implements ConstantExpression<T> {
	// remember the containing term?
	public Type<T> type;

	public T value; // the currently bound value

	public Parameter(SimpleString n,Type<T> t) {
		super(n);
		type = t;
	}
	public Parameter(Type<T> t) {
		type = t;
	}
	
	public TypeCode typeCode() {
		return type.typeCode();
	}
	
	public T value(State s) {
		return value;
	}
	
	public History<SimpleVoid> storage(State p, State c) {
		return null;
	}
	
	public IdentifierCode idCode() {
		return IdentifierCode.Parameter;
	}
	
	public boolean apply(State p, int contextID, State c) {
		if (value != ANMLBoolean.True)
			return false;
		return true;
	}
	
	transient public PDDL.Parameter asPDDLParameter;
	
	public PDDL.Parameter asPDDLParameter() {
		return asPDDLParameter;
	}
	
	public PDDL.ParameterReference translateArgument(PDDL pddl, Interval unit) {
		return asPDDLParameter.ref;
	}
	
	void _translateDecl(PDDL pddl) {
		if (name == Interval.startName || name == Interval.durationName || name == Interval.endName || name == Interval.braName || name == Interval.ketName)
			return;
		
		if (typeCode() == TypeCode.Symbol || typeCode() == TypeCode.Object) {
			if (pddl.depth > 0) {
				StringBuilder buf = new StringBuilder(name.toString());
				buf.append('_').append(pddl.depth);
				asPDDLParameter = pddl.new Parameter(buf.toString(),type.asPDDLType());
				if (type.asPDDLType() == null)
					System.err.println("Null type?");
			} else {
				asPDDLParameter = pddl.new Parameter(name.toString(),type.asPDDLType());
				if (type.asPDDLType() == null) {
					System.err.println("Null type?");
				}
			}
		} else {
			System.err.println("Cannot translate parameter '" + name + "' of type '" + type.name() + "' (" + typeCode() + ").");
		}
	}
	
	public void translateDecl(PDDL pddl, Interval unit) {
		if (asPDDLParameter != null)
			return;
		_translateDecl(pddl);
		if (asPDDLParameter != null) {
			unit.getPDDLParameters().add(asPDDLParameter);
		}
	}
		
	public void translateDecl(PDDL pddl, PDDL.Function realPDDL) {
		if (asPDDLParameter != null)
			return;
		_translateDecl(pddl);
		if (asPDDLParameter != null) {
			realPDDL.parameters.add(asPDDLParameter);
		}				
	}
	public void translateDecl(PDDL pddl, PDDL.Predicate boolPDDL) {
		if (asPDDLParameter != null)
			return;
		_translateDecl(pddl);
		if (asPDDLParameter != null) {
			boolPDDL.parameters.add(asPDDLParameter);
		}				
	}
	
}
